#include "stdafx.h"
#include "xKernel/IxDraw.h"
#include "xKernel/IxBuilder.h"
#include "AttributeFunc.h"

CxThunk::CxThunk()
    : POP_EAX(0x58)
    , PUSH(0x68)
    , m_this(0)
    , PUSH_EAX(0x50)
    , JMP(0xE9)
    , m_method(0)
{}

void CxThunk::Attach(unsigned int pThis)
{
    m_this = pThis;
}

void CxThunk::AttachMethod(unsigned int pMethod)
{
    m_method = pMethod - (PointerToUINT(&JMP) + sizeof(JMP) + sizeof(m_method));
}

HRESULT CxCallMethod::CallMethod(unsigned int unThis, unsigned int unMethod, INT index, IxPairVec* pVec)
{
    m_oThunk.Attach(unThis);
    m_oThunk.AttachMethod(unMethod);
    return S_OK;
}

#define CALLMETHOD_IMPL(type)                                                                                       \
HRESULT CxCallMethod##type::CallMethod(unsigned int unThis, unsigned int unMethod, INT index, IxPairVec* pVec)      \
{                                                                                                                   \
    __super::CallMethod(unThis, unMethod, index, pVec);                                                             \
    typedef HRESULT (__stdcall * FUNCTION)(type);                                                                   \
    FUNCTION func = (FUNCTION)&m_oThunk;                                                                            \
    CComBSTR bsValue;                                                                                               \
    pVec->GetStr(index, &bsValue);                                                                                  \
    type value = ::xBase::WCHAR2##type(bsValue);                                                                    \
    return func(value);                                                                                             \
}

CALLMETHOD_IMPL(INT)
CALLMETHOD_IMPL(BOOL)
CALLMETHOD_IMPL(BYTE)
CALLMETHOD_IMPL(POINT)
CALLMETHOD_IMPL(SIZE)
CALLMETHOD_IMPL(RECT)
CALLMETHOD_IMPL(COLORREF)

HRESULT CxCallMethodBSTR::CallMethod(unsigned int unThis, unsigned int unMethod, INT index, IxPairVec* pVec)
{
    __super::CallMethod(unThis, unMethod, index, pVec);
    typedef HRESULT (__stdcall * FUNCTION)(BSTR);
    FUNCTION func = (FUNCTION)&m_oThunk;
    CComBSTR bsValue;
    pVec->GetStr(index, &bsValue);
    return func(bsValue);
}

HRESULT CxCallMethodIxDraw::CallMethod(unsigned int unThis, unsigned int unMethod, INT index, IxPairVec* pVec)
{
    __super::CallMethod(unThis, unMethod, index, pVec);
    typedef HRESULT (__stdcall * FUNCTION)(IxDraw* pDraw);
    FUNCTION func = (FUNCTION)&m_oThunk;
    CComPtr<IxPairVec> spDesc;
    pVec->GetInterface(index, __uuidof(IxPairVec), (void**)&spDesc);
    CComPtr<IxBuilder> spBuilder;
    ::xCommon::GetService(__uuidof(IxBuilder), (void**)&spBuilder);
    if (spBuilder)
    {
        CComPtr<IUnknown> spUnk;
        spBuilder->CreateFromDescription(spDesc, &spUnk);
        CComQIPtr<IxDraw> spDraw = spUnk;
        if (spDraw)
        {
            return func(spDraw);
        }
    }
    return E_FAIL;
}

HRESULT CxCallMethodAlignment::CallMethod(unsigned int unThis, unsigned int unMethod, INT index, IxPairVec* pVec)
{
    __super::CallMethod(unThis, unMethod, index, pVec);
    typedef HRESULT (__stdcall * FUNCTION)(INT);
    FUNCTION func = (FUNCTION)&m_oThunk;
    CComBSTR bsValue;
    pVec->GetStr(index, &bsValue);

    INT value = xKernel::GetAlignment(bsValue);

    return func(value);
}